/*
 *  Shader for showing the region of influence.
 *  November 2008,
 *  Essex Edwards
 */

#include <OGF/quick_start/shaders/quick_start_surface_shader3d.h>
#include <OGF/surface/grob/surface.h>

#include <OGF/renderer/context/rendering_context.h>
#include <OGF/renderer/pipeline/rendering_pipeline.h>
#include <OGF/cells/map/map_attributes.h>
#include <OGF/cells/map/geometry.h>
#include <OGF/cells/map/map_cell_heap.h>

#include <OGF/quick_start/common/deform.h>

namespace OGF {

    DeformSurfaceShader3d::DeformSurfaceShader3d(
        Surface* surface
    ) : PlainSurfaceShader3d(surface) {

		color[0] = Color(1,1,0,1);
		for(int i=1;i<10;i++)
		{
			double r = 1.0 - (i-1)/8.0;
			double g = 0;
			double b = (i-1)/8.0;
			color[i] = Color(r,g,b,1);
		}
    }

	/**
	* Draw the vertices with their normals.
	*/
    void DeformSurfaceShader3d::draw_vertices(RenderingContext* context)
	{
		static Color Normal_Color(0.2, 0.2, 0.8, 1);

	//	PlainSurfaceShader3d::draw_vertices(context);
		
		MapTexVertexNormal normal_map(surface()) ;
		
		double length = surface()->bbox().radius()/40.0;

        RenderingPipeline* pipeline = context->pipeline() ;
        pipeline->color(Normal_Color) ;
        disable_lighting(context) ;

		pipeline->begin(RenderingPipeline::SEGMENTS) ;
		FOR_EACH_VERTEX(Map, surface(), it)
		{
			Map::Vertex* v = it;
			Vector3d normal = normal_map[ v->halfedge()->tex_vertex() ];

			pipeline->vertex(it->point()) ;
			pipeline->vertex(it->point() + length*normal) ;
		}
        pipeline->end(RenderingPipeline::SEGMENTS) ;
	}

	/**
	* Draw the entire shader, just the plain shader but with my new things too.
	*/
    void DeformSurfaceShader3d::draw(RenderingContext* context)
	{
		draw_anchor(context);
		draw_border(context);
		draw_roi(context);

		PlainSurfaceShader3d::draw(context);
	}

	/**
	* Draw a big dot for the anchor, and a line for its normal.
	*/
	void DeformSurfaceShader3d::draw_anchor(RenderingContext* context)
	{	
		static Color Anchor_Color(1.0, 0.0, 0.0, 1);
		static Color Norm_Color(1.0, 0.0, 0.0, 1);
		static Color New_Norm_Color(0.0, 0.0, 1.0, 1);

		deform.lazy_init(this->surface());

		Map::Vertex *anchor = deform.get_anchor();

		if(anchor == nil) //draw nothing if there is no anchor
			return;

        RenderingPipeline* pipeline = context->pipeline() ;
        disable_lighting(context) ;
        pipeline->color(Anchor_Color) ;
        pipeline->set_point_size(10) ;
    
		//Draw the anchor vertex
		pipeline->begin(RenderingPipeline::POINTS) ;
			pipeline->vertex(anchor->point());
        pipeline->end(RenderingPipeline::POINTS) ;

		//And draw the normal		
        MapTexVertexNormal normal(surface()) ;
		Vector3d real_norm = normal[anchor->halfedge()->tex_vertex()];

		double base_size = surface()->bbox().radius()/20.0;
		double length_real = 2*base_size;
		double length_new = 4*base_size;

		Point3d start =  anchor->point();

		Point3d real_end = start + length_real * real_norm;

		pipeline->begin(RenderingPipeline::SEGMENTS) ;
			pipeline->color(Norm_Color) ;
			pipeline->vertex(anchor->point()) ;
			pipeline->vertex(real_end) ;
        pipeline->end(RenderingPipeline::SEGMENTS) ;
	}
	/**
	* Draw border faces Blue.
	*/
	void DeformSurfaceShader3d::draw_border(RenderingContext* context)
	{
		static Color Border_Color(0.0, 0.0, 1.0, 1);
		deform.lazy_init(this->surface());

        enable_lighting(context) ;
        RenderingPipeline* pipeline = context->pipeline() ;
        pipeline->color(Border_Color) ;
        pipeline->set_shading_mode(RenderingPipeline::SHADE_SMOOTH) ;
        MapTexVertexNormal normal(surface()) ;
        FOR_EACH_FACET(Map,surface(), it) 
		{
			Map::Facet* facet = &(*it);
			if(deform.is_on_border(facet))
			{
				pipeline->begin(RenderingPipeline::POLYGON) ;
				Map::Halfedge* jt = it->halfedge() ;
				do {
					pipeline->normal(normal[jt->tex_vertex()]) ;
					pipeline->vertex(jt->vertex()->point()) ;
					jt = jt->next() ;
				} while(jt != it->halfedge()) ;
				pipeline->end(RenderingPipeline::POLYGON) ;
			}
        }
	}
	/**
	* Draw the region of influence in gold?
	*/
	void DeformSurfaceShader3d::draw_roi(RenderingContext* context)
	{
		static Color ROI_Color(1.0, 1.0, 0.6, 1);
		deform.lazy_init(this->surface());
		
        enable_lighting(context) ;
        RenderingPipeline* pipeline = context->pipeline() ;
        pipeline->color(ROI_Color) ;
        pipeline->set_shading_mode(RenderingPipeline::SHADE_SMOOTH) ;
        MapTexVertexNormal normal(surface()) ;
        FOR_EACH_FACET(Map,surface(), it) 
		{
			Map::Facet* facet = &(*it);
			if(deform.is_in_region(facet))
			{
				pipeline->begin(RenderingPipeline::POLYGON) ;
				Map::Halfedge* jt = it->halfedge() ;
				do {
					pipeline->normal(normal[jt->tex_vertex()]) ;
					pipeline->vertex(jt->vertex()->point()) ;
					jt = jt->next() ;
				} while(jt != it->halfedge()) ;
				pipeline->end(RenderingPipeline::POLYGON) ;
			}
        }
	}
}
